using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.Reflection;
using System.ComponentModel.Design.Serialization;
using System.CodeDom;
using GuavaData;
using System.Drawing.Design;

namespace GuavaLib
{
    [Designer(typeof(GDataGridViewDesigner))]
    public partial class GDataGridView : DataGridView, Guava
    {
        DataView dv;
        Guid gid;
        string gname;
        Label lab;
        
        public GDataGridView()
            : base()
        {
            this.AutoGenerateColumns = false;
        }


        public System.Windows.Forms.Label Label
        {
            get { return lab; }
            set { lab = value; }
        }

        #region Guava Members

        [Browsable(false)]
        public LaunchType LType
        {
            get { return LaunchType.NA; }
        }

        [Browsable(false)]
        public ControlType CType
        {
            get { return ControlType.Entity; }
        }

        [Browsable(false)]
        public string GText
        {
            get
            {
                if (this.lab == null) return null;
                return this.lab.Text;
            }
        }

        public string GName
        {
            get
            {
                if (this.gname == null) return this.Name;
                return gname;
            }
            set
            {
                gname = value;
            }
        }

        [Browsable(false)]
        public Point GLocation
        {
            get { return this.Location; }
        }

        [Browsable(false)]
        public Size GSize
        {
            get { return this.Size; }
        }

        [Browsable(false)]
        public List<Guava> GComponents
        {
            get
            {
                List<Guava> lg = new List<Guava>();
                foreach (DataGridViewColumn dc in this.Columns) lg.Add(dc as Guava);
                return lg;
            }
        }

        public void GBind(string table, int i)
        {
            DataRow dr = AppData.ds.Tables[table].Rows[i];
            gid = (Guid) dr["id"];
            this.DefaultValuesNeeded += new DataGridViewRowEventHandler(GDGVDefaultValuesNeeded);

            // Find parent and attach persistence handler
            Control p = this.Parent;
            while (!(p is GuavaForm))
            {
                if (p == null) return;
                p = p.Parent;
            }
            GuavaForm gf = p as GuavaForm;
            gf.PersistSignal += new GuavaData.SignalToPersist(gf_PersistSignal);
            
            // Attach cell template data to current lookup data
            foreach (GDataGridViewColumn gdgvc in this.Columns)
            {
                if (gdgvc.GDomain is GuavaData.Domain.Lookup)
                {
                    // Attach data
                    DataGridViewComboBoxCell dgvcc = (gdgvc.CellTemplate) as DataGridViewComboBoxCell;
                    List<object> agl = gdgvc.GDomain.ListOutput();
                    dgvcc.Items.Clear();
                    foreach (object o in agl) dgvcc.Items.Add(o);
                }
            }

            // Create a view of the destination table that only has the current ID's
            AppData.FetchRowsByFK(this.GName, gid);
            dv = (new DataView(AppData.ds.Tables[this.GName], "fk='" + gid.ToString() + "'", null, DataViewRowState.CurrentRows));
            dv.AllowNew = true;
            dv.AllowEdit = true;
            dv.AllowDelete = true;

            DataGridViewColumn did = new DataGridViewColumn(new DataGridViewTextBoxCell());
            did.Name = "id";
            did.DataPropertyName = "id";
            did.HeaderText = "id";
            did.Visible = false;

            DataGridViewColumn dfk = new DataGridViewColumn(new DataGridViewTextBoxCell());
            dfk.Name = "fk";
            dfk.DataPropertyName = "fk";
            dfk.HeaderText = "fk";
            dfk.Visible = false;

            this.Columns.Add(did);
            this.Columns.Add(dfk);

            this.DataSource = dv;
        }

        [Browsable(false)]
        public string GDefault
        {
            get { return null; }
        }

        [Browsable(false)]
        public string GToolTip
        {
            get
            {
                Control p = this.TopLevelControl;
                if (!(p is Guava)) return null;
                ToolTip t = (p as GuavaForm).GToolTipProvider;
                if (t == null) return null;

                // Fetch the tooltip and return it
                return t.GetToolTip(this);
            }
        }

        [Browsable(false)]
        public GuavaData.Domain.Domain GDomain
        {
            get { return new GuavaData.Domain.UniqueIdentifier(); }
        }

        [Browsable(false)]
        public Guava this[string s]
        {
            get
            {
                foreach (Guava g in this.GComponents) if (g.GName == s) return g;
                return null;
            }
        }

        #endregion

        void gf_PersistSignal(object sender, PersistSignalEventArgs e)
        {
            if (e.bPersist) PersistChanges();
            else dv.Table.RejectChanges();
        }

        private void PersistChanges()
        {
            // Purge deleted rows
            dv.RowStateFilter = DataViewRowState.Deleted;
            foreach (DataRowView drv in dv)
                AppData.DeleteRow(dv.Table.TableName, (Guid)drv["id"]);

            // Modify old rows
            dv.RowStateFilter = DataViewRowState.ModifiedCurrent;
            foreach (DataRowView drv in dv)
                AppData.CommitRow(dv.Table.TableName, (Guid)drv["id"], DMLType.UPDATE);

            // Add new rows
            dv.RowStateFilter = DataViewRowState.Added;
            foreach (DataRowView drv in dv)
                AppData.CommitRow(dv.Table.TableName, (Guid)drv["id"], DMLType.INSERT);

            // Finish
            dv.RowStateFilter = DataViewRowState.CurrentRows;
            dv.Table.AcceptChanges();
        }
        
        private void GDGVDefaultValuesNeeded(object sender, System.Windows.Forms.DataGridViewRowEventArgs e)
        {
            e.Row.Cells["fk"].Value = gid;
            e.Row.Cells["id"].Value = Guid.NewGuid();
        }

        #region Column Editor

        [Editor(typeof(GDataGridViewCollectionEditor), typeof(UITypeEditor))]
        public new DataGridViewColumnCollection Columns
        {
            get
            {
                return base.Columns;
            }
        }

        internal class GDataGridViewCollectionEditor : CollectionEditor
        {
            public GDataGridViewCollectionEditor(System.Type type)
                : base(type)
            {
            }

            protected override Type CreateCollectionItemType()
            {
                return typeof(GDataGridViewColumn);
            }

            protected override object CreateInstance(Type itemType)
            {
                return base.CreateInstance(itemType);
            }
        }

        #endregion
        
        #region "GDataGridViewDesigner"

        internal interface IEventHandlerService
        {
            // Events
            event EventHandler EventHandlerChanged;

            // Methods
            object GetHandler(Type handlerType);

            void PopHandler(object handler);

            void PushHandler(object handler);


            // Properties
            Control FocusWindow { get; }

        }

        internal class GDataGridViewDesigner : System.Windows.Forms.Design.ParentControlDesigner
        {

            #region "Private Instance Variables of GDataGridViewDesigner"

            private DesignerVerbCollection m_verbs = new DesignerVerbCollection();
            private IDesignerHost m_DesignerHost;

            #endregion

            #region Public GDataGridViewDesigner Methods
            public GDataGridViewDesigner()
                : base()
            {
                DesignerVerb verb1 = new DesignerVerb("Add Column", new EventHandler(OnAddColumn));
                m_verbs.Add(verb1);
            }

            public override void Initialize(IComponent component)
            {
                base.Initialize(component);
                ((GDataGridView)component).GotFocus += new EventHandler(this.OnGotFocus);
            }
            #endregion

            #region Properties

            public override DesignerVerbCollection Verbs
            {
                get
                {
                    return m_verbs;
                }
            }

            public IDesignerHost DesignerHost
            {
                get
                {
                    if (m_DesignerHost == null)
                        m_DesignerHost = (IDesignerHost)(GetService(typeof(IDesignerHost)));

                    return m_DesignerHost;
                }
            }

            #endregion

            #region "GDataGridView Designer Events"

            private void OnGotFocus(object sender, EventArgs e)
            {
                IEventHandlerService service1 = (IEventHandlerService)this.GetService(typeof(IEventHandlerService));
                if (service1 != null)
                {
                    Control control1 = service1.FocusWindow;
                    if (control1 != null)
                    {
                        control1.Focus();
                    }
                }
            }

            void OnAddColumn(Object sender, EventArgs e)
            {
                GuavaLib.GDataGridView ParentControl = (GuavaLib.GDataGridView)Control;
                DataGridViewColumnCollection oldColumns = ParentControl.Columns;

                InitialColumnDefinitionForm icdf = new InitialColumnDefinitionForm();
                if (icdf.ShowDialog() == DialogResult.Cancel) return;

                RaiseComponentChanging(TypeDescriptor.GetProperties(ParentControl)["Columns"]);

                GuavaLib.GDataGridViewColumn P = (GuavaLib.GDataGridViewColumn)(DesignerHost.CreateComponent(typeof(GuavaLib.GDataGridViewColumn)));
                P.HeaderText = icdf.ColumnName;
                P.DataPropertyName = icdf.ColumnName;
                P.GName = icdf.ColumnName;
                P.GDomain = icdf.ColumnDomain;
                ParentControl.Columns.Add(P);

                RaiseComponentChanged(TypeDescriptor.GetProperties(ParentControl)["Columns"], oldColumns, ParentControl.Columns);
            }
            #endregion
        }
        #endregion
    }
}
